package com.unittec.drainage.provider.manage.utils;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.io.WKBReader;
import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.linearref.LengthIndexedLine;

import java.text.DecimalFormat;
import java.util.List;


/**
 *
 * @author Jason
 */
public class JtsUtils {

    private static final double EARTH_RADIUS = 6378137;
    public static GeometryFactory factory = new GeometryFactory(new PrecisionModel(100000000000d));
    private static DecimalFormat df = new DecimalFormat("0.00000000000");
    private static DecimalFormat format = new DecimalFormat("0.0000");
    public static int SRID_4547 = 4547;

    public static String toEwkt(Geometry geom) {
        if (geom == null) {
            return null;
        }
        String type = geom.getGeometryType().toUpperCase();
        switch (type) {
            case "POINT": {
                Coordinate coor = geom.getCoordinate();
                return "POINT(" + formatCoordinateNoZ(coor) + ")";
            }
            case "MULTIPOINT": {
                return coordinateToEwkt("MULTIPOINT(", geom.getCoordinates(), ")");
            }
            case "LINESTRING": {
                return coordinateToEwkt("LINESTRING(", geom.getCoordinates(), ")");
            }
            case "POLYGON": {
                return coordinateToEwkt("POLYGON((", geom.getCoordinates(), "))");
            }
            case "MULTILINESTRING": {
                StringBuffer sb = new StringBuffer();
                sb.append("MULTILINESTRING(");
                sb.append(multiGeometryFormat(geom));
                sb.append(")");
                return sb.toString();
            }
            case "MULTIPOLYGON": {
                StringBuffer sb = new StringBuffer();
                sb.append("MULTIPOLYGON(");
                sb.append(multiGeometryFormat(geom));
                sb.append(")");
                return sb.toString();
            }
            case "GEOMETRYCOLLECTION": {
                StringBuffer sb = new StringBuffer();
                int num = geom.getNumGeometries();
                sb.append("GEOMETRYCOLLECTION(");
                for (int j = 0; j < num; j++) {
                    Geometry element = geom.getGeometryN(j);
                    String subType = element.getGeometryType().toUpperCase();
                    if ("POINT".equals(subType)) {
                        sb.append("POINT(" + formatCoordinate(element.getCoordinate()) + ")");
                    } else if ("LINESTRING".equals(subType)) {
                        sb.append(coordinateToEwkt("LINESTRING(", element.getCoordinates(), ")"));
                    } else if ("POLYGON".equals(subType)) {
                        sb.append(coordinateToEwkt("POLYGON((", element.getCoordinates(), "))"));
                    }
                    if (j < num - 1) {
                        sb.append(",");
                    }
                }
                sb.append(")");
                return sb.toString();
            }
        }
        return null;
    }

    private static String formatCoordinate(Coordinate coordinate) {
        if (Double.isNaN(coordinate.z)) {
            coordinate.z = 0;
        }
        return df.format(coordinate.x) + " " + df.format(coordinate.y) + " " + (coordinate.z != 0 ? df.format(coordinate.z) : "0");
    }


    /**
     * 不含Z坐标
     *
     * @param coordinate
     * @return
     */
    private static String formatCoordinateNoZ(Coordinate coordinate) {
        return df.format(coordinate.x) + " " + df.format(coordinate.y);
    }

    /**
     * 不含Z坐标
     *
     * @param coordinates
     * @return
     */
    private static String formatCoordinateNoZ(Coordinate[] coordinates) {
        String str = "";
        for (int i = 0; i < coordinates.length; i++) {
            Coordinate coordinate = coordinates[i];
            str += (df.format(coordinate.x) + " " + df.format(coordinate.y) + ",");
        }
        if (str.endsWith(",")) {
            str = str.substring(0, str.length() - 1);
        }
        return str;


    }

    public static String coordinateToEwkt(String prefix, Coordinate[] coordinates, String suffix) {
        StringBuffer sb = new StringBuffer();
        sb.append(prefix);
        boolean append = false;
        for (Coordinate coordinate : coordinates) {
            if (append) {
                sb.append(",");
            }
            sb.append(formatCoordinateNoZ(coordinate));
            append = true;
        }
        sb.append(suffix);
        return sb.toString();
    }

    public static String multiGeometryFormat(Geometry geom) {
        StringBuffer sb = new StringBuffer();
        int num = geom.getNumGeometries();
        for (int i = 0; i < num; i++) {
            Geometry g = geom.getGeometryN(i);
            sb.append(coordinateToEwkt("((", g.getCoordinates(), "))"));
            if (i < num - 1) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

    /**
     * 获取两组成的线的几何中心
     *
     * @param s 起始点
     * @param e 结束点
     * @return
     */
    public static Coordinate getCentroid(Coordinate s, Coordinate e) {// 获取两点组成的线的图心
        if (s.x == e.x && s.y == e.y) {
            return s;
        }
        LineString ls = factory.createLineString(new Coordinate[]{s, e});
        Point cp = ls.getCentroid();
        return cp.getCoordinate();
    }

    /**
     * 获取多个离散几何点的几何中心
     *
     * @param coors
     * @return
     */
    public static Coordinate getCentroid(Coordinate[] coors) {
        MultiPoint mp = factory.createMultiPoint(coors);
        return mp.getCentroid().getCoordinate();
    }

    /**
     * 获取线的中心点
     *
     * @param line
     * @return
     */
    public static Coordinate getCenter(LineString line) {
        LengthIndexedLine indexedLine = new LengthIndexedLine(line);
        double[] index = indexedLine.indicesOf(line);
        Coordinate mid = indexedLine.extractPoint((index[0] + index[1]) / 2);
        return mid;
    }


    /**
     * 创建点
     *
     * @param coordinate
     * @param SRID
     * @return
     */
    public static Point createPoint(Coordinate coordinate, int SRID) {
        Point point = factory.createPoint(coordinate);
        point.setSRID(SRID);
        return point;
    }

    /**
     * 创建点
     *
     * @param x    x坐标
     * @param y    y坐标
     * @param SRID
     * @return
     */
    public static Point createPoint(double x, double y, int SRID) {
        Point point = factory.createPoint(new Coordinate(x, y));
        point.setSRID(SRID);
        return point;
    }

    /**
     * 创建线
     *
     * @param coordinates
     * @param SRID
     * @return
     */
    public static LineString createLineString(Coordinate[] coordinates, int SRID) {
        LineString line = factory.createLineString(coordinates);
        line.setSRID(SRID);
        return line;
    }

    /**
     * 创建线
     *
     * @param pointList
     * @param SRID
     * @return
     */
    public static LineString createLineString(List<Geometry> pointList, int SRID) {
        Coordinate[] coordinates = new Coordinate[pointList.size()];
        for (int i = 0; i < pointList.size(); i++) {
            Geometry geom = pointList.get(i);
            geom.setSRID(SRID);
            coordinates[i] = geom.getCoordinate();
        }
        LineString line = factory.createLineString(coordinates);
        line.setSRID(SRID);
        return line;
    }

    /**
     * 创建面
     *
     * @param coors
     * @return
     */
    public static Polygon createPolygon(Coordinate[] coors) {
        return factory.createPolygon(coors);
    }

    /**
     * 创建面
     *
     * @param coors
     * @param SRID
     * @return
     */
    public static Polygon createPolygon(Coordinate[] coors , int SRID) {
        Polygon polygon = factory.createPolygon(coors);
        polygon.setSRID(SRID);
        return polygon;
    }

    /**
     * 创建面
     *
     * @param pointList
     * @param SRID
     * @return
     */
    public static Polygon createPolygon(List<Geometry> pointList, int SRID) {
        Coordinate[] coordinates = new Coordinate[pointList.size()];
        for (int i = 0; i < pointList.size(); i++) {
            Geometry geom = pointList.get(i);
            geom.setSRID(SRID);
            coordinates[i] = geom.getCoordinate();
        }
        Polygon polygon = factory.createPolygon(coordinates);
        polygon.setSRID(SRID);
        return polygon;
    }

    /**
     *  wkt转化成geometry
     *
     * @param wkt
     * @return
     */
    public static Geometry getGeometryFromWkt(String wkt) {
        WKTReader reader = new WKTReader();
        Geometry geometry = null;
        try {
            geometry = reader.read(wkt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (geometry == null) {
            return null;
        }
        return geometry;
    }

    public static Geometry getGeometryFromWkb(String wkb) {
        WKBReader reader = new WKBReader();
        Geometry geometry = null;
        try {
            geometry = reader.read(WKBReader.hexToBytes(wkb));
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (geometry == null) {
            return null;
        }
        return geometry;
    }

}
